import { editor, languages, MarkerSeverity, Position } from '../fillers/monaco-editor-core';
import { IWorkerImmutable } from '../baseWorker';
import { BaseWorker } from '../baseWorker';
import { IWorker } from '../languageFeatures';
import { worker } from 'monaco-editor';
import { CycloneParser, CodeFormatter, SyntaxError } from 'cyclone-parser';

export interface ITypeImmutable extends IWorkerImmutable {
	/**
	 * Used in completion
	 */
	extraTypeName?: string[];
}

export class TypeWorker extends BaseWorker implements IWorker {
	public constructor(ctx: worker.IWorkerContext, createData: ITypeImmutable) {
		super(ctx, createData);
	}
	private static formatter = new CodeFormatter();
	private static parser = new CycloneParser();

	async doComplete(uri: string, position: Position): Promise<languages.CompletionList | null> {
		//TODO
		return null;
	}
	async doHover(uri: string, position: Position): Promise<languages.Hover | null> {
		return null;
	}
	async format(
		uri: string,
		range: Range | null,
		options: languages.FormattingOptions
	): Promise<languages.TextEdit[]> {
		const contents: languages.TextEdit[] = [];
		const code = this.getScriptText(uri);
		if (code) {
			const annot = TypeWorker.formatter.formatTypeAnnotation(code, {
				prettify: true,
				preserveComment: true
			});
			//TODO may show ex
			const ast = TypeWorker.parser.parse({
				valueRaw: annot,
				type: 'type',
				locations: true
			});

			contents.push({
				text: annot,
				range: {
					startLineNumber: 1,
					endLineNumber: ast.loc!.end.line,
					startColumn: 1,
					endColumn: ast.loc!.end.column
				}
			});
		}
		return contents;
	}

	async getSemanticDiagnostics(uri: string): Promise<editor.IMarkerData[]> {
		//TODO
		console.log('Validating semantic ', uri);
		return [];
	}

	async getSyntacticDiagnostics(uri: string): Promise<editor.IMarkerData[]> {
		const errors = new Array<editor.IMarkerData>();
		const annot = this.getScriptText(uri);
		console.log('Validating syntax ', uri);
		console.log(annot);

		if (!annot) return errors;
		try {
			TypeWorker.parser.parse({ valueRaw: annot, type: 'type' });
		} catch (e) {
			if (e instanceof SyntaxError) {
				errors.push({
					severity: MarkerSeverity.Error,
					message: e.message,
					startLineNumber: e.location.line,
					endLineNumber: e.location.line,
					startColumn: e.location.column,
					endColumn: e.location.column
				});
			} else throw e;
		}
		return errors;
	}

	async parserTreeToString(uri: string): Promise<any> {
		const annot = this.getScriptText(uri);

		if (!annot) return;
		try {
			return JSON.stringify(TypeWorker.parser.parse({ valueRaw: annot, type: 'type' }));
		} catch (e) {
			if (e instanceof SyntaxError) {
				return JSON.stringify(e);
			} else throw e;
		}
	}
}

export function create(ctx: worker.IWorkerContext, createData: ITypeImmutable): TypeWorker {
	return new TypeWorker(ctx, createData);
}
